#include "Font.h"
//#include "../ASprite.h"
#include "Game.h"
#include "Memory.h"
//#include "../sprite_def_m25.h"

#include <stdarg.h>
#include <stdio.h>

#define RGBA(r,g,b,a)(b|(g<<8)|(r<<16)|(a<<24))
#undef RGB
#define RGB(r,g,b) RGBA(r,g,b, 0xff)


//*mg UBERHACK!!!
bool inDrawShadow = false;

const int kColorTable[]={
	RGB(0x00,0x00,0x00),
	RGB(0xA0,0x00,0x00),
	RGB(0xe5,0xcd,0x00),
	RGB(0x00,0xA0,0x00),
	RGB(0x00,0x80,0x00),
	RGB(0x00,0x00,0xA0),
	RGB(0x00,0x80,0x00),
	RGB(0xA0,0x00,0x00),
	RGB(0x00,0x80,0x00),
	RGB(0x00,0x00,0x00),
};

#define JP_FAME_ID 0
ASprite* Font::mpJapinese[2] = {NULL, NULL};
int Font::miGapXJapanese[2] = {2, 5};
int Font::miGapYJapanese[2] = {0, 5};
#define is_digit(c)     ((c) >= FONT_NUM_0 && (c) <= FONT_NUM_9)
static int skip_atoi(const GL_TCHAR **s);
static int skip_atoh(const GL_TCHAR **s,unsigned int max=-1);

#ifdef _DEBUG_FONT
GL_UCHAR tmp;
//convet utf8->unicode,return offset chars
int convert (const GL_TCHAR *in, GL_UCHAR * pOut, size_t num)
{
	int i = 0;
	while(*in && (size_t)i < num)
	{
		size_t count = 0;
		GL_TCHAR ch = *in;
		while(ch&0x80)
		{
			ch <<= 1;
			count++;
		}
		*pOut = 0x00FF;
		*pOut = (*in++) & (*pOut >> count);
		if(count)
		{
			i += count--;
		}
		else
			i++;
		while(count)
		{
			*pOut <<=6;
			*pOut |= (*in++)&0x3F;
			count--;
		}
		pOut++;
	}
	return i;
}

#endif
GL_UCHAR  Font::GetIndexFromChar(const GL_TCHAR* &ch)
{

#ifdef _DEBUG_FONT
	if(*ch & 0x80)
		_curAsprite = mpJapinese;
	else
		_curAsprite = mpASprite;
	GL_UCHAR tmp;
	GL_UCHAR  idx = 0;
	ch += convert(ch,&tmp,1);
	for( int i = 0; i < sizeof(_order)/sizeof(_order[0])-1;++idx)
	{
		GL_UCHAR tmp2;
		int offset = convert((GL_TCHAR*)&_order[i],&tmp2,1);
		ASSERT(offset > 0);
		i += offset;
		if(tmp2 == tmp)
		{
			return idx+1;
		}
	}
	//ASSERT(false);
	return (GL_UCHAR)1;
#else
	GL_UCHAR  value;
	// RUIZD: Never set the japinese font. Change later when the text is readeable
	if ((((int)(*ch)) & 0x80) != 0)
	{
/*		if(ch[1] == 4)
		{
			_curAsprite = mpJapinese[mpUseJapanese];
			value=4;
			ch += 2;
		}
		else
		{*/
			//ASSERT((ch[1] & 0x80) != 0);
			_curAsprite = mpJapinese[mpUseJapanese];
			value=(ch[0] & 0x7F) | ((ch[1] & 0x7F) << 7);
			ch += 2;
//		}
	}
	else
	{
		_curAsprite = mpASprite;
		value = *ch++;
	}
	return value;
#endif
}
Font::Font(void)
:mclrLayerIdx(Blue)
, miGapX(0)
, miGapY(0)
, mpASprite(NULL)
, mbNeedFree(false)
, miSpaceWidth(4)
, miSpaceHeight(4)
, miTexColorNum(0)
, miCurrentAlpha(0xff)
, mpUseJapanese(0)
{
	//mCharSectionMap[CM_JANPANESE] = JAPANESE_MD_0X2026;
}
Font::~Font(void)
{
	Release();
}
void Font::Release()
{
	if(mbNeedFree)
	{		
		SAFE_DELETE(mpASprite);
		mbNeedFree = false;
	}
}
bool Font::DrawTime(tIPLTime& t,int x, int y, int align)
{
	const GL_TCHAR fmt[]={	FONT_PERCENT,FONT_NUM_0,FONT_NUM_2,FONT_LOWERCASE_D,FONT_COLON,
		FONT_PERCENT,FONT_NUM_0,FONT_NUM_2,FONT_LOWERCASE_D,FONT_COLON,
		FONT_PERCENT,FONT_NUM_0,FONT_NUM_2,FONT_LOWERCASE_D,0 };
	return DrawText2(x,y,align,fmt,t.mHour,t.mMinute, t.mSecond);
}

bool Font::DrawPercent(int num,int x, int y, int align)
{
	const GL_TCHAR fmt[] = {FONT_PERCENT,FONT_LOWERCASE_D,FONT_PERCENT,FONT_PERCENT,0};
	return DrawText2(x,y,align,fmt,num);
}

int Font::DrawCelcius(int num,int x, int y, int align)
{
	const GL_TCHAR fmt[] = {FONT_PERCENT,FONT_LOWERCASE_D,0};
	//for(int i = 0; i < 256; i++)
	//{
	//	logToOut("%d -> %c", i, i);
	//}
	GL_TCHAR text[5];
	int len=Font::sprintf(text, fmt, num);
	DrawText2(x,y,align,fmt,num);
	return len;
}

bool Font::DrawNumber(int num,int x, int y, int align)
{
	const GL_TCHAR fmt[] = {FONT_PERCENT,FONT_LOWERCASE_D,0};
	GL_TCHAR buf[20];
	int n=sprintf(buf,fmt,num);
	ASSERT(n<10);
	if(n > 3)	
	{
		GL_TCHAR* end=buf+n+(n-1)/3;
		GL_TCHAR* ebuf=buf+n;
		GL_TCHAR split=FONT_COMMA;
		
		for(int i=0;i<n+(n-1)/3;++i)
		{
			if(i%4==0&&i>0)
				*end--=split;
			else
				*end--=*ebuf--;
		}
		ASSERT(end==ebuf&& ebuf==buf);
	}
	return DrawText2(buf,x,y,-1,align);
}

bool Font::DrawNumber2(int num,int x, int y, int align, bool endingDot)
{
	if (endingDot)
	{
		GL_TCHAR fmt[] = {FONT_PERCENT,FONT_LOWERCASE_D, FONT_POINT, 0};
		return DrawText2(x,y,align,fmt,num);
	}
	else
	{
		GL_TCHAR fmt[] = {FONT_PERCENT,FONT_LOWERCASE_D,0};
		return DrawText2(x,y,align,fmt,num);
	}
}

int  Font::sprintf(GL_TCHAR* buf, const GL_TCHAR* fmt,...)
{
	va_list a;
	va_start(a,fmt);
	return Font::vsprintf(buf,fmt,a);
}
GL_TCHAR* Font::strucpy(GL_TCHAR* src,const GL_TCHAR* dst,size_t length)
{
	size_t i;
	for(i=0; i < length && dst && dst[i]; ++i)
	{
		if(dst[i]>=FONT_LOWERCASE_A && dst[i] <=FONT_LOWERCASE_Z)
			src[i] = dst[i] - FONT_LOWERCASE_A + FONT_UPPERCASE_A;
		else
			src[i] = dst[i];
	}
	src[i] = 0;
	return src;
}
void Font::LoadFontImage(const char*filename)
{
	ASSERT(mpASprite);
	mpASprite->LoadImage(filename);
}
#ifdef _OptimizePaintFrame
void Font::BeginOutIn(const GL_TCHAR *text, T_S32 objIdx, T_F32 inScale, T_S32 ox, T_S32 oy)
{
	T_S32 _textW_d2 = GetTextWidth2( text ) / 2;
	mpASprite->BeginFrmOutIn( objIdx, inScale, ox+_textW_d2, oy );
}
void Font::EndOutIn()
{
	mpASprite->EndFrmOutIn();
}
#endif
void Font::DrawText2OutIn(const GL_TCHAR *text,int x, int y, size_t length,int align)
{
#ifdef _OptimizePaintFrame
	T_S32 _textW_d2 = GetTextWidth2( text ) / 2;
	mpASprite->BeginFrmOutIn( (int)text, 1.0f, x+_textW_d2, y );
	DrawText2( text, x, y, length, align );
	mpASprite->EndFrmOutIn();
#else
	DrawText2( text, x, y, length, align );
#endif
}
bool Font::DrawTextNumber2(float x, float y, int align,const GL_TCHAR *text, int num)
{
	const GL_TCHAR fmt[] = {FONT_PERCENT,FONT_LOWERCASE_D,0};
	GL_TCHAR buf[20];
	GL_TCHAR tmp[256];
	int n=sprintf(buf,fmt,num);
	ASSERT(n<10);
	if(n > 3)
	{
		GL_TCHAR* end=buf+n+(n-1)/3;
		GL_TCHAR* ebuf=buf+n;
		GL_TCHAR split=FONT_COMMA;
		
		for(int i=0;i<n+(n-1)/3;++i)
		{
			if(i%4==0&&i>0)
				*end--=split;
			else
				*end--=*ebuf--;
		}
		ASSERT(end==ebuf&& ebuf==buf);
	}
	strcpy((char*) tmp, (char*) text);
	strcat((char*) tmp, (char*) buf);
	return DrawText2(tmp,x,y,-1,align);
}
bool Font::DrawText2(float x, float y, int align,  const GL_TCHAR*fmt,...)
{
	GL_TCHAR text[256];
	va_list a;
	va_start(a,fmt);
	int len=Font::vsprintf(text, fmt, a);
	return DrawText2(text,x,y,len,align);
}
bool Font::DrawMultiText(const GL_TCHAR *text,int x, int y, const int nLinesLength[],
						 int nTextDisplayLength, int textAlign, bool forceShadow)
{
	if(*text == NULL || *text == 0) return true;
	mclrStackHead = mTexStackHead;

	// fix verticall alignment
	{
		int lines = 0;
		int _nTextDisplayLength = nTextDisplayLength;
		while (_nTextDisplayLength > 0)
		{
			_nTextDisplayLength -= nLinesLength[lines];
			lines++;
		}
		int lineHeight = miGapY + miSpaceHeight;
		int textHeight = lines * lineHeight;
		if (textAlign & Bottom)
		{
			if (textAlign & Top) // VCenter
				y -= textHeight / 2;
			else
				y -= textHeight;
		}
		textAlign = textAlign & (~VCenter);
	}

	while(*text && nTextDisplayLength > 0 && *nLinesLength > 0)
	{
		int length = nTextDisplayLength > *nLinesLength ? *nLinesLength : nTextDisplayLength;

		DrawShadow(text, x, y, length, textAlign, forceShadow); // for JP

		for(int i=0; i< miTexColorNum; ++i)
		{
			currentTexture = i;
			int color = miTexColor[i][mclrStackHead];
			int alpha = CMath::Min(miCurrentAlpha, (color >> 24) & 0xff);
			getGfx()->SetTexColor(TO_ARGB(alpha, (color >> 16) & 0xff, (color >> 8) & 0xff, (color >> 0) & 0xff));
			SetColor( i );
			DrawText(text, x, y, length, textAlign);
		}
		text += *nLinesLength;
		nTextDisplayLength -= *nLinesLength++;
		y += miSpaceHeight+miGapY;
	}
	return nTextDisplayLength == 0;
}
Font::ControlFlag Font::SkipWhiteSpace(const GL_TCHAR* & text, int& ow)
{
	int oh;
	ControlFlag flag;
	do{
		flag = ControlText(text,ow,oh);
	}while(flag == FLAG_SPACE);
	return flag;
}
static int _nLinesLength[TEXT_MAX_LINES];
static int _nMaxLine;
static int _dialogHeight;
static int _dialogWidth;
static const GL_TCHAR *_curText=NULL;

bool Font::DrawMultiText(const GL_TCHAR *text,int x, int y,size_t length, int textAlign, int _dialogWidth, int _dialogHeight)
{
	int TextLines = GetTextLines(text, _dialogWidth, _dialogHeight, _nMaxLine, _nLinesLength);
	unsigned int TextCount = 0;
	for (int i = 0; i < TextLines; ++i)
	{
		TextCount += _nLinesLength[i];
	}
	_curText = text;
	return DrawMultiText(_curText, x, y, _nLinesLength, TextCount, textAlign);
}

/**
 * @note:
 * This method was created because all the rotation system of the engine is working very bad.
 * I've only 2 days to reach the dealine and that's why I wrote this... I didn't like it at all.
 */
bool Font::DrawTextRotated(const GL_TCHAR *text,int x, int y, T_F32 angle)
{
	if(*text == NULL || *text == 0) return true;

	int textAlign = Font::HCenter|Font::Top;
	int _x = x;
	int _y = y;

	if (angle == 0)
	{
		// dummy case
	}
	else if (angle == 90)
	{
		_x = y;
		_y = (x + (GetTextWidth2(text) >> 1)) + 100;
	}
	else if (angle == 180)
	{
		textAlign = Font::Left|Font::Top;
		_x = (x) + (GetTextWidth2(text) >> 1);
		_y += (SCREEN_WIDTH_D2 >> 1) - (miSpaceHeight);
	}
	else if (angle == -90)
	{
		_x = y + (miSpaceHeight >> 1);// + (SCREEN_WIDTH_D2 - (miSpaceHeight >> 1));
		_y = ((x+100) - (GetTextWidth2(text) >> 1));
	}
	else
	{
		return false;
	}

	GFX_SetRotate(angle);


	int lenght = STRLEN(text);
	DrawShadow(text, _x, _y, lenght, textAlign);

	for(int i=0; i< miTexColorNum; ++i)
	{
		int color = miTexColor[i][mclrStackHead];
		int alpha = CMath::Min(miCurrentAlpha, (color >> 24) & 0xff);
		getGfx()->SetTexColor(TO_ARGB(alpha, (color >> 16) & 0xff, (color >> 8) & 0xff, (color >> 0) & 0xff));
		SetColor( i );
		currentTexture = i;
		DrawText(text, _x, _y, lenght, textAlign);
	}

	GFX_ResetRotate();
	return true;
}

int Font::GetTextLines(const GL_TCHAR *begin, int & nMaxWidth, int &nMaxHeight, int &nMaxLine, int* nLinesLength,
					   unsigned int nTextLength)
{
	if(begin == NULL || *begin == 0) return 0;
	int nLinesCount = 0;
	int max_with = 0;
	const GL_TCHAR* now;
	int width;
	const GL_TCHAR* next;
	bool skipWord=false;
	int _ox = 0;

	do
	{
		skipWord=true;
sentence:
		now = begin;
		width = 0;
		do
		{
			//ASSERT(*now != FONT_SPACE);
			next = now;
			ControlFlag flag;
			if(skipWord)
				flag= SkipWord(next,width);//skip word
			else
				flag= SkipChar(next,width);

			if(width - miGapX > nMaxWidth)
			{
				if(now == begin)
				{
					skipWord = false;
					goto sentence;
				}
				else
				{
					break;// too longer
				}
			} 
			//else if(g_LanguageInternalId == LANG_JP)
			//{
			//	_ox += width;
			//	int i;
			//	while(*next && _ox < nMaxWidth && flag != FLAG_SENTANCE)
			//	{
			//		if(*next == FONT_STICK)
			//		{
			//			next += 2;
			//		}
			//		for(i = 0; i < next[i] != 0 && next[i] != FONT_STICK && _ox < nMaxWidth; i += 2)
			//		{
			//			const GL_TCHAR *tmp = (next + i);
			//			GL_UCHAR value = GetIndexFromChar(tmp);
			//			int index = GetFrameIndex(value);
			//			if(value >= 126)
			//			{
			//				_ox += _curAsprite->GetModuleWidth(index) + miGapXJapanese[mpUseJapanese];
			//			}
			//		}
			//		next += i;
			//		if(_ox > nMaxWidth)
			//		{
			//			next -= i;
			//			flag = FLAG_SENTANCE;
			//			_ox = 0;
			//		}
			//	}
			//}
			now = next;
			max_with = CMath::Max(max_with, width);
			if(flag == FLAG_SENTANCE || SkipWhiteSpace(now,width) == FLAG_SENTANCE)
				break; //force linebreak
			if(width > nMaxWidth) break;
		}while(unsigned(now - begin) < nTextLength && *now);
		SkipWhiteSpace(now,width);
		int lineLength = now - begin;
		ASSERT(lineLength > 0);
		if (nLinesLength != NULL) nLinesLength[nLinesCount] = lineLength;
		if (_nLinesLength != NULL) _nLinesLength[nLinesCount++] = lineLength;
		ASSERT(nLinesCount < TEXT_MAX_LINES);
		nTextLength -= lineLength;
		begin = now;
	} while(nTextLength > 0 && *begin);
	nMaxWidth = max_with;
	nMaxLine  = nMaxHeight/(miSpaceHeight+miGapY);
	nMaxHeight = (nLinesCount > nMaxLine ? nMaxLine : nLinesCount) * (miSpaceHeight+miGapY);
	return nLinesCount;
}
//////////////////////////////////////////////////////////////////////////
// new font design
#undef NUM_BASE
#define SYMBOLS_BASE    1
#define NUM_BASE        MAP_NUM_0
#define UPPERCASE_BASE  MAP_UPPERCASE_A
#define LOWERCASE_BASE  MAP_LOWERCASE_A
#define EXTENDCASE_BASE (MAP_LOWERCASE_Z+1)
#define JANPANESE_BASE  126
#define CHARMAP_COUNT   1105
const int kCharSectionOffset[Font::CM_COUNT] = {SYMBOLS_BASE,NUM_BASE,UPPERCASE_BASE,LOWERCASE_BASE,EXTENDCASE_BASE,JANPANESE_BASE};
Font::CharMapCategory Font::GetCharCategory(GL_UCHAR charIndex)
{
	if(charIndex < NUM_BASE)
		return CM_SYMBOLS;
	else if (charIndex < UPPERCASE_BASE)
		return CM_NUM;
	else if(charIndex<LOWERCASE_BASE)
		return CM_UPPERCASE;
	else if (charIndex< EXTENDCASE_BASE)
		return CM_LOWERCASE;
	else if (charIndex< JANPANESE_BASE)
		return CM_EXTENDCASE;
	else/* if (charIndex< CHARMAP_COUNT)*/
		return CM_JANPANESE;
	/*return (CharMapCategory)-1;*/
}
int  Font::GetFrameIndex(GL_UCHAR charIndex)
{
	if(charIndex <48)
	{
		if(charIndex == 32)
			charIndex = 0;
		
	}
	else if(charIndex <58)
	{
		charIndex -=32;
	}
	else if(charIndex <65)
	{
		if(charIndex == 58)
			charIndex = 26;
	}
	else if(charIndex <91)
	{
		charIndex-=34;
	}
	else if(charIndex <97)
	{
		
	}
	else if(charIndex <123)
	{
		charIndex-=36;
	}
	CharMapCategory categ = GetCharCategory(charIndex);
	ASSERT(mCharSectionMap[categ] != -1);
	return mCharSectionMap[categ] + charIndex - kCharSectionOffset[categ];

}
int Font::GetCharWidth(const GL_TCHAR *ch)
{
#ifdef _DEBUG_FONT
	int index = GetFrameIndex(GetIndexFromChar(ch));
#else
	int index = GetFrameIndex(*ch);
#endif
	return mpASprite->GetFrameWidth(index);
}
int Font::DrawChar(const GL_TCHAR *ch,int x, int y,int align)
{
	mpASprite->SetCurrentPalette(mclrLayerIdx);
	int offsetX = x;
	int offsetY = y;
	if( align & Right)
	{
		int textWidth = GetCharWidth(ch);
		if (align & Left)
			offsetX = x - textWidth / 2;
		else
			offsetX = x - textWidth;
	}
	if (align & Bottom)
	{
		int textHeight = GetCharWidth(ch);
		if (align & Top)
			offsetY = y - textHeight / 2;
		else
			offsetY = y - textHeight;
	}
	x = offsetX;
	y = offsetY;
#ifdef _DEBUG_FONT
	int index = GetFrameIndex(GetIndexFromChar(ch));
#else
	int index = GetFrameIndex(*ch);
#endif
	for(int i=0; i< miTexColorNum; ++i)
	{
		int color = miTexColor[i][mTexStackHead];
		int alpha = CMath::Min(miCurrentAlpha, (color >> 24) & 0xff);
		getGfx()->SetTexColor(TO_ARGB(alpha, (color >> 16) & 0xff, (color >> 8) & 0xff, (color >> 0) & 0xff));
		SetColor( i );
		//result=DrawText(text,x,y,length,align);
		mpASprite->PaintFrame(index, x, y );
	}

	return mpASprite->GetFrameWidth(index);
}

int Font::GetCharIndex(const GL_TCHAR *text, GL_TCHAR *str)
{
	if(text == NULL || *text == 0) return 0;
	int ox = 0;
	int oy = 0;
	int width = 0;
	GL_TCHAR *strToFind = str;
	size_t length = STRLEN(text);
	while(*text && length)
	{
		const GL_TCHAR * cur = text;
		if(!ControlText(text,ox,oy))
		{
			if (*text == *strToFind)
			{
				strToFind++;

				if (!*strToFind)
				{
					return ox;
				}
			}
			else
			{
				strToFind = str;
			}

			GL_UCHAR value = GetIndexFromChar(text);
			int index = GetFrameIndex(value);
			if(*cur&0x80)
				ox += mpJapinese[mpUseJapanese]->GetModuleWidth(index) + miGapXJapanese[mpUseJapanese];
			else
				ox += _curAsprite->GetFrameWidth(index) + miGapX;
			if(ox > width) width = ox;
		}
		length -= POINTER_TO_VAL(text) - POINTER_TO_VAL(cur);
	}
	if(ox > width) width = ox;
	return width;
}

int Font::GetTextWidth2(const GL_TCHAR*text, size_t length)
{
	if(text == NULL || *text == 0) return 0;
	int ox = 0;
	int oy = 0;
	int width = 0;
	while(*text && length)
	{
		const GL_TCHAR * cur = text;
		if(!ControlText(text,ox,oy))
		{
			GL_UCHAR value = GetIndexFromChar(text);
			int index = GetFrameIndex(value);
			if(*cur&0x80)
			{
				ox += mpJapinese[mpUseJapanese]->GetModuleWidth(index) + miGapXJapanese[mpUseJapanese];
			}
			else
			{
				ox += _curAsprite->GetFrameWidth(index) + miGapX;
			}
			if(ox > width) width = ox;
		}
		length -= POINTER_TO_VAL(text) - POINTER_TO_VAL(cur);
	}
	if(ox > width) width = ox;
	return width;
}

int Font::GetTextHeight2(const GL_TCHAR*text, size_t length)
{
	if(text == NULL || *text == 0) return 0;
	int ox = 0;
	int oy = 0;
	int height = 0;
	while(*text && length)
	{
		const GL_TCHAR * cur = text;
		if(!ControlText(text,ox,oy))
		{
			GL_UCHAR value = GetIndexFromChar(text);
			int index = GetFrameIndex(value);
			if(oy > height) height = oy;
		}
		length -= POINTER_TO_VAL(text) - POINTER_TO_VAL(cur);
	}
	return height + miSpaceHeight;
}
void Font::SetColor(int index)
{
	CheckP( mpASprite );
	if(index >=0 && index < mpASprite->_img_num /*&&g_LanguageInternalId != CGame::LANG_JP*/)
	{
		mclrLayerIdx = index;
		mpASprite->SetCurrentPalette(mclrLayerIdx);
	}
}
void Font::SetTexColor(int c,...)
{
	CheckP( mpASprite );
	va_list a;
	mTexStackHead = 0;
	mclrStackHead = 0;
	currentTexture = 0;
	miTexColorNum = mpASprite->_img_num;
	ASSERT(miTexColorNum <= MAX_TEX_COLOR_NUM);
	miTexColor[miTexColorNum-1][mclrStackHead] = c;
	va_start(a,c);
	// what is this ASSERT for?
	//ASSERT(miTexColor[0][mclrStackHead]&0xff000000);
	for(int i=miTexColorNum-2; i>=0; --i)
	{
		miTexColor[i][mclrStackHead] = va_arg(a,int);
		// what is this ASSERT for?
		//ASSERT(miTexColor[i][mclrStackHead]&0xff000000);
	}
	va_end(a);
}

int g_fontTestIndex = 2;

void Font::DrawShadow(const GL_TCHAR *text,int x, int y, size_t length, int align, bool forceShadow)
{
	inDrawShadow = true;
	// apply shadow to JP font
	inDrawShadow = false;
}

bool Font::DrawText2(const GL_TCHAR *text,float x, float y, size_t length,int align)
{
	bool result;
	if(miTexColorNum == 0)
	{
		currentTexture = 0;
		result = DrawText(text,x,y,length,align);
	}
	else
	{
		DrawShadow(text, x, y, length, align); // for JP

		for(int i=0; i< miTexColorNum; ++i)
		{
			mclrStackHead = mTexStackHead;
			currentTexture = i;
			int color = miTexColor[i][mclrStackHead];
			int alpha = CMath::Min(miCurrentAlpha, (color >> 24) & 0xff);
			getGfx()->SetTexColor(TO_ARGB(alpha, (color >> 16) & 0xff, (color >> 8) & 0xff, (color >> 0) & 0xff));
			SetColor( i );
			result=DrawText(text,x,y,length,align);
		}
	}
	return result;
}
Font::ControlFlag Font::SkipChar(const GL_TCHAR* &text,int &ox)
{
	int oy;
	ControlFlag flag = ControlText(text,ox,oy);
	if(flag == FLAG_NONE)
	{
		GL_UCHAR value = GetIndexFromChar(text);
		int index = GetFrameIndex(value);
		if(value >= JANPANESE_BASE)
			ox += mpJapinese[mpUseJapanese]->GetModuleWidth(index) + miGapXJapanese[mpUseJapanese];
		else
			ox += _curAsprite->GetFrameWidth(index) + miGapX;
	}
	return flag;
}

#define is_punct_sbc(value)  ((value >= 131 && value<=137)||(value<MAP_NUM_0))
#define is_punct(value)  (value == FONT_MINUS)/*(value < MAP_NUM_0)*/
Font::ControlFlag Font::SkipWord(const GL_TCHAR* &text,int &width)
{

	bool isalpha = (*text & 0x80 ) == 0;
	int ox=width, oy;
	ControlFlag flag;
	bool isSpace;
	do{
		flag = ControlText(text,ox,oy);
		if(flag == FLAG_NONE)
		{
			GL_UCHAR value = GetIndexFromChar(text);
			int index = GetFrameIndex(value);
			if(value >= JANPANESE_BASE)
			{
				// RUIZD: WTF? No fucking japanese here, please. Change the line for a hardcoded character
				ox += mpJapinese[mpUseJapanese]->GetModuleWidth(index) + miGapXJapanese[mpUseJapanese];
				//ox += _curAsprite->GetFrameWidth(0) + miGapX;
			}
			else
			{
				ox += _curAsprite->GetFrameWidth(index) + miGapX;
			}
			if(is_punct(value) /*|| (isalpha != (value < JANPANESE_BASE))*/ /*|| (g_LanguageInternalId == LANG_JP && is_punct_sbc(value))*/)
			{
				break;
			}
			width = ox;
		}
		isSpace = (*text == FONT_SPACE);
		// in FR allow spaces only if they are not followed by "?" or "!"

	} while (*text && (!isSpace) && flag != FLAG_WORD && flag != FLAG_SENTANCE);
	if (flag != FLAG_SENTANCE) width = ox;
	return flag;
}
int Font::SkipWord(const GL_TCHAR*text)
{
	int ox;
	const GL_TCHAR * cur = text;
	SkipWord(cur, ox);
	return POINTER_TO_VAL(cur)- POINTER_TO_VAL(text);
}
void Font::AlignText(const GL_TCHAR*text, int &x, int &y, size_t &length,int align)
{
	if( align & Right)
	{
		int textWidth = GetTextWidth2(text,length)/**IPLMath_FixedToFloat(g2DCommRI.scaleX)*/;
		if (align & Left)
			x -= textWidth / 2;
		else
			x -= textWidth;
	}
	if (align & Bottom)
	{
		int textHeight = GetTextHeight2(text,length)/**IPLMath_FixedToFloat(g2DCommRI.scaleY)*/;
		if (align & Top)
			y -= textHeight / 2;
		else
			y -= textHeight;
	}
}

Font::ControlFlag Font::ControlText(const GL_TCHAR* &text, int &ox, int&oy)
{
	int layer;
	ControlFlag flags=FLAG_NONE;
	switch(*text)
	{
	case FONT_STICK://
		if(*++text == FONT_STICK)
		{
			text++;
			ox = 0;
			oy += miGapY + miSpaceHeight;
			flags = FLAG_SENTANCE;
		}
		else
		{
			flags = FLAG_WORD;
		}
		break;
	case FONT_SPACE:
		ox += miSpaceWidth + miGapX;
		++text;
		/*
		// in FR allow spaces flags if they are not followed by "?" or "!"
		if (g_LanguageInternalId == LANG_FR && (*text))
		{
			GL_TCHAR nextChar = (*text);
			if (nextChar != MAP_QST_MARK && nextChar != MAP_EXCL)
			{
				flags = FLAG_SPACE;
			}
		}
		else
		*/
		{
			flags = FLAG_SPACE;
		}
		break;
	case FONT_GTR://>> or >|
		++text;
		if(*text == FONT_GTR)
		{
			flags = FLAG_PAGE_CONTINUE;
			++text;
		}
		else if (*text == FONT_STICK)
		{
			flags = FLAG_PAGE_STOP;
			++text;
		}
		else
		{
			flags = FLAG_NONE;
			text -= 2;
		}
		break;
	case FONT_POUND://color control
		ASSERT(miTexColorNum > 0);
		layer=miTexColorNum;
		do{
			++text;
			--layer;
			if(is_digit(*text))//current layer
			{//#c1|c2|c3... c? is [0-9]
				if(inDrawShadow)
				{
					if((*text - FONT_NUM_0) == 0 || (*text - FONT_NUM_0) == 9 )
					{
						miTexColor[layer][mclrStackHead+1] = TO_ARGB(0x44, 0xFF, 0xFF, 0xFF);
					}
					else
					{
						miTexColor[layer][mclrStackHead+1] = TO_ARGB(0x44, 0, 0, 0);;
					}					
					flags = FLAG_PUSH_COLOR;					
				}
				else
				{
					miTexColor[layer][mclrStackHead+1] = kColorTable[*text - FONT_NUM_0];
					ASSERT(mclrStackHead < 2);
					flags = FLAG_PUSH_COLOR;
				}
			}
			else
			{//# finish
				flags = FLAG_POP_COLOR;
				break;
			}
			++text;
		}while(*text == FONT_STICK);
		break;
	}
	return flags;
}

bool Font::DrawText(const GL_TCHAR*text,float fx, float fy, size_t length,int align)
{
	int x = fx * SCREEN_WIDTH / (TALL_BY_METERS * RATIO_SCREEN);
	int y = fy * SCREEN_HEIGHT / TALL_BY_METERS;
	if(length == -1)
	{
		length = Font::StrLen(text);
	}

	if( text == NULL || *text==0) return true;
	AlignText(text,x, y, length, align);
	int _ox = 0;
	int _oy = miGapY;
	_curAsprite = NULL;
	ASprite * _oldsprte=NULL;
	int oldcategory=-1;
	while(*text && length)
	{
		const GL_TCHAR * cur = text;
		ControlFlag flag = FLAG_NONE;//ControlText(text,_ox,_oy);

		// in ControlText(), _ox is set to 0 after a ||
		// In this function _ox begins with miGapX, so thats the value it must have.
		//if (_ox == 0 && flag == FLAG_SENTANCE)
		//{
		//	_ox = miGapX;
		//}

		if(flag == FLAG_NONE)
		{
			int category;
			GL_UCHAR value = GetIndexFromChar(text);
			if( _curAsprite == NULL ) return true;
			if(value < JANPANESE_BASE) category=0;
			else category = 1;
			//else if(value < JANPANESE_BASE+680)category=1;
			//else category = 2;
			//if(_oldsprte != _curAsprite/*||category!=oldcategory*/)
			if(category!=oldcategory || _oldsprte== NULL)
			{
				oldcategory=category;
				if(_oldsprte!=NULL)_oldsprte->EndBatchFrm();
				//mpJapinese->SetCurrentPalette(category);
				_curAsprite->BeginBatchFrm( fx, fy );
				if(miTexColorNum>0)
				{
					//ASSERT((miTexColor[mclrLayerIdx][mclrStackHead]&0xFF000000)==0xFF000000);
					int color = miTexColor[mclrLayerIdx][mclrStackHead];
					int alpha = CMath::Min(miCurrentAlpha, (color >> 24) & 0xff);
					getGfx()->SetTexColor(TO_ARGB(alpha, (color >> 16) & 0xff, (color >> 8) & 0xff, (color >> 0) & 0xff));
				}
				_oldsprte = _curAsprite;
			}
			int index = GetFrameIndex(value);
			
			if(mclrLayerIdx < _curAsprite->_img_num)
				_curAsprite->AddFModule(0,index,_ox,_oy);
				
				//_curAsprite->AddFrm(index,_ox,_oy);
			_ox += _curAsprite->GetModuleWidth(index) + miGapX;
			
		}
		else if (flag == FLAG_POP_COLOR)
		{
			if(!inDrawShadow && (miTexColorNum == 1 || (miTexColorNum > 1 && currentTexture == 1)))
			{
				ASSERT(mclrStackHead>0);
				--mclrStackHead;
				if(_oldsprte) _curAsprite->EndBatchFrm();
				_oldsprte = NULL;
			}
		}
		else if (flag == FLAG_PUSH_COLOR)
		{
			if(!inDrawShadow && (miTexColorNum == 1 || (miTexColorNum > 1 && currentTexture == 1)))
			{
				ASSERT(mclrStackHead==0);
				++mclrStackHead;
				if(_oldsprte) _curAsprite->EndBatchFrm();
				_oldsprte = NULL;
			}
		}
		length -= POINTER_TO_VAL(text) - POINTER_TO_VAL(cur);
	}
	if(_oldsprte!=NULL)_oldsprte->EndBatchFrm();
	return !(*text);
}
void Font::SetFont2(ASprite*pFont, FontStyle style, bool bNeedFree,int anchor)
{
	//Release();
	mpASprite = pFont;
	mbNeedFree = bNeedFree;
	miAnchor = anchor;

	if( style == FontGame)
	{
		mCharSectionMap[CM_SYMBOLS]   = TEXT_WHITE_FRAME_SYMBOLS;
		mCharSectionMap[CM_NUM]       = TEXT_WHITE_FRAME_NUM;
		mCharSectionMap[CM_UPPERCASE] = TEXT_WHITE_FRAME_UPPERCASE;
		mCharSectionMap[CM_LOWERCASE] = TEXT_WHITE_FRAME_LOWERCASE;
		mCharSectionMap[CM_EXTENDCASE] = TEXT_WHITE_FRAME_EXTENDCASE;
		SetTexColor(0xFFFFFFFF, RGBA(0x00,0x00,0x88,0xFF));
		miSpaceWidth = 12;
		miSpaceHeight = 29;
		miGapX=-5;
	}
	else if(style == FontTitle)
	{
/*
		mCharSectionMap[CM_SYMBOLS]   = TEXT_FOCUS_FRAME_SYMBOLS;
		mCharSectionMap[CM_NUM]       = -1;//EXT_FOCUS_FRAME_NUM;
		mCharSectionMap[CM_UPPERCASE] = TEXT_FOCUS_FRAME_UPPERCASE;
		mCharSectionMap[CM_LOWERCASE] = TEXT_FOCUS_FRAME_UPPERCASE;
		mCharSectionMap[CM_EXTENDCASE] = TEXT_FOCUS_FRAME_EXTENDCASE;
		if(g_LanguageInternalId != LANG_JP )
		{
			miGapX = -3;
			miSpaceWidth = 10;
			miSpaceHeight = 18;
		}
		else
		{
			miGapX = 2;
			miSpaceWidth = 14;
			miSpaceHeight = 16;
		}
*/
	}
	else if(style == FontSmall)
	{
		mCharSectionMap[CM_SYMBOLS]    = FONT3_FRAME_SYMBOL;
		mCharSectionMap[CM_NUM]        = FONT3_FRAME_NUM;
		mCharSectionMap[CM_UPPERCASE]  = FONT3_FRAME_UPPERCASE;
		mCharSectionMap[CM_LOWERCASE]  = FONT3_FRAME_LOWERCASE;
		mCharSectionMap[CM_EXTENDCASE] = FONT3_FRAME_EXTENDCASE;
		
		miSpaceWidth = 8;
		miSpaceHeight = 15;
		miGapX = 1;
		miGapY = 2;
		
		SetTexColor(RGBA(0x0,0x0,0x0,0xff));
	}
	else if(style == FontNormal)
	{
		mCharSectionMap[CM_SYMBOLS]    = FONT01_FRAME_SYMBOLS;
		mCharSectionMap[CM_NUM]        = FONT01_FRAME_NUM;
		mCharSectionMap[CM_UPPERCASE]  = FONT01_FRAME_UPPERCASE;
		mCharSectionMap[CM_LOWERCASE]  = FONT01_FRAME_LOWERCASE;
		mCharSectionMap[CM_EXTENDCASE] = FONT01_FRAME_EXTENDCASE;
		
		miSpaceWidth = 8;
		miSpaceHeight = 30;
		miGapX = 0;
		miGapY = 0;
		
		SetTexColor(RGBA(0xff,0xff,0xff,0xff),RGBA(0x0,0x0,0xff,0xff));
	}
	else if(style == FontNormalSmall)
	{
		mCharSectionMap[CM_SYMBOLS]    = FONT02_FRAME_SYMBOLS;
		mCharSectionMap[CM_NUM]        = FONT02_FRAME_NUM;
		mCharSectionMap[CM_UPPERCASE]  = FONT02_FRAME_UPPERCASE;
		mCharSectionMap[CM_LOWERCASE]  = FONT02_FRAME_LOWERCASE;
		mCharSectionMap[CM_EXTENDCASE] = FONT02_FRAME_EXTENDCASE;

		miSpaceWidth = 8;
		miSpaceHeight = 30;
		miGapX = 0;
		miGapY = 0;
		
		SetTexColor(RGBA(0xff,0xff,0xff,0xff),RGBA(0x0,0x0,0xff,0xff));
	}

	//else if (style == FontExtra)
	//{
	//	ASSERT(false);
	//	//mCharSectionMap[CM_SYMBOLS]    = -1;//FONT04_FRAME_SYMBOLS;
	//	//mCharSectionMap[CM_NUM]        = FONT05_FRAME_NUM;
	//	//mCharSectionMap[CM_UPPERCASE]  = FONT05_FRAME_UPPERCASE;
	//	//mCharSectionMap[CM_LOWERCASE]  = FONT05_FRAME_LOWERCASE;
	//	//mCharSectionMap[CM_EXTENDCASE] = -1;
	//}
	else if(style == FontUser)
	{
		mCharSectionMap[CM_SYMBOLS]    = -1;
		mCharSectionMap[CM_NUM]        = -1;
		mCharSectionMap[CM_UPPERCASE]  = -1;
		mCharSectionMap[CM_LOWERCASE]  = -1;
		mCharSectionMap[CM_EXTENDCASE] = -1;
	}
}
void Font::LoadGameFont()
{
	Release();


	//SAFE_DELETE(mpASprite);
	int index;

	index =5;//gp_GameApp->miGameColor;

	if(index < 0)
		index = 0;
	ASprite* sprite = GL_NEW ASprite("font_small.ssp");
	sprite->LoadImage("font_small.bbm");
	SetFont2(sprite,FontGame);
	//SetJapaneseAsprite();
	
}
void Font::LoadTitleFont()
{
	mpUseJapanese = 1;

	Release();


	SAFE_DELETE(mpASprite);
	int index;

	index =5;//gp_GameApp->miGameColor;

	if(index < 0)
		index = 0;
	//SetFont2(GL_NEW ASprite(SPRITE_TEXT_FOCUS,index%5,-1),FontTitle);
	
}

void Font::LoadSmallFont2()
{
	Release();

	SetFont2(GL_NEW ASprite(SPRITE_FONT3), FontSmall);
	
}
void Font::LoadNoramlFont2()
{
	mpUseJapanese = 1;

	Release();

		//SAFE_DELETE(mpASprite);
	ASprite* sprite = GL_NEW ASprite("font_small.ssp");
	sprite->LoadImage("font_small.bbm");
	SetFont2(sprite, FontNormal);
	
}

void Font::LoadNormalSmallFont()
{
	mpUseJapanese = 1;

	Release();

	SetFont2( GetResManager()->getSprite(SPRITE_FONT_SMALL), FontNormalSmall);
	
}

void Font::InitJapaneseFont()
{
	/*if (mpJapinese[0] == NULL)
	{
		mpJapinese[0] = GL_NEW ASprite(SPRITE_JAPANESE);
		mpJapinese[1] = GL_NEW ASprite(SPRITE_JAPANESE2);
	}*/
}

void Font::ReleaseJapaneseFont()
{
	/*int iSprite;
	for (iSprite = 0; iSprite < SPRITE_JAPANESE_COUNT; iSprite++)
	{
		if (mpJapinese[iSprite] != NULL)
		{
			SAFE_DELETE(mpJapinese[iSprite]);
		}
	}*/
}

void Font::SetJapaneseAsprite()
{
	/*Font::InitJapaneseFont();
	mpASprite = mpJapinese[mpUseJapanese];
	mbNeedFree = false;
	miSpaceWidth = 8;
	miSpaceHeight = 20;
	miGapX = miGapXJapanese[mpUseJapanese];
	miGapY = miGapYJapanese[mpUseJapanese];
	SetTexColor(RGBA(0x0,0x0,0x0,0xff));
	mCharSectionMap[CM_SYMBOLS] = JAPANESE_FRAME_SYMBOL;
	mCharSectionMap[CM_UPPERCASE] = JAPANESE_FRAME_UPPERCASE;
	mCharSectionMap[CM_LOWERCASE] = JAPANESE_FRAME_LOWERCASE;
	mCharSectionMap[CM_NUM] = JAPANESE_FRAME_NUM;
	mCharSectionMap[CM_EXTENDCASE] = JAPANESE_FRAME_EXTENDED_CASE;
	mCharSectionMap[CM_JANPANESE] = JAPANESE_MD_0X2026;*/
}
void Font::LoadExtraFont2()
{
	//Release();
}

static int skip_atoi(const GL_TCHAR **s)
{
	int i=0;
	while (is_digit(**s))
		i = i*10 + *((*s)++) - FONT_NUM_0;
	return i;
}
static int skip_atoh(const GL_TCHAR **s, unsigned int max)
{
	int i=0;
	while (max-- > 0)
	{
		if(is_digit(**s))
			i = i*16 + *((*s)++) - FONT_NUM_0;
		else if((**s) >= FONT_UPPERCASE_A && (**s) <= FONT_UPPERCASE_F)
			i = i*16 + *((*s)++) - FONT_UPPERCASE_A+10;
		else
			break;
	}
	return i;
}
#define ZEROPAD 1               /* pad with zero */
#define SIGN    2               /* unsigned/signed long */
#define PLUS    4               /* show plus */
#define SPACE   8               /* space if plus */
#define LEFT    16              /* left justified */
#define SPECIAL 32              /* 0x */
#define SMALL   64              /* use 'abcdef' instead of 'ABCDEF' */
static GL_TCHAR * number(GL_TCHAR * str, int num, int base, int size, int precision,int type)
{
	GL_TCHAR c,sign,tmp[36];
	const GL_TCHAR upper[] = { FONT_NUM_0, FONT_NUM_1, FONT_NUM_2, FONT_NUM_3, FONT_NUM_4, FONT_NUM_5, FONT_NUM_6, FONT_NUM_7, FONT_NUM_8, FONT_NUM_9,
		FONT_UPPERCASE_A, FONT_UPPERCASE_B, FONT_UPPERCASE_C, FONT_UPPERCASE_D, FONT_UPPERCASE_E, FONT_UPPERCASE_F, FONT_UPPERCASE_G, FONT_UPPERCASE_H,
		FONT_UPPERCASE_I, FONT_UPPERCASE_J, FONT_UPPERCASE_K, FONT_UPPERCASE_L, FONT_UPPERCASE_M, FONT_UPPERCASE_N, FONT_UPPERCASE_O, FONT_UPPERCASE_P,
		FONT_UPPERCASE_Q, FONT_UPPERCASE_R, FONT_UPPERCASE_S, FONT_UPPERCASE_T, FONT_UPPERCASE_U, FONT_UPPERCASE_V, FONT_UPPERCASE_W, FONT_UPPERCASE_X,
		FONT_UPPERCASE_Y, FONT_UPPERCASE_Z};
	const GL_TCHAR lower[] = { FONT_NUM_0, FONT_NUM_1, FONT_NUM_2, FONT_NUM_3, FONT_NUM_4, FONT_NUM_5, FONT_NUM_6, FONT_NUM_7, FONT_NUM_8, FONT_NUM_9,
		FONT_LOWERCASE_A, FONT_LOWERCASE_B, FONT_LOWERCASE_C, FONT_LOWERCASE_D, FONT_LOWERCASE_E, FONT_LOWERCASE_F, FONT_LOWERCASE_G, FONT_LOWERCASE_H,
		FONT_LOWERCASE_I, FONT_LOWERCASE_J, FONT_LOWERCASE_K, FONT_LOWERCASE_L, FONT_LOWERCASE_M, FONT_LOWERCASE_N, FONT_LOWERCASE_O, FONT_LOWERCASE_P,
		FONT_LOWERCASE_Q, FONT_LOWERCASE_R, FONT_LOWERCASE_S, FONT_LOWERCASE_T, FONT_LOWERCASE_U, FONT_LOWERCASE_V, FONT_LOWERCASE_W, FONT_LOWERCASE_X,
		FONT_LOWERCASE_Y, FONT_LOWERCASE_Z};
	const GL_TCHAR * digits = upper;
	int i;

	if (type&SMALL) digits=lower;
	if (type&LEFT) type &= ~ZEROPAD;
	if (base<2 || base>36)
		return 0;
	c = (type & ZEROPAD) ? FONT_NUM_0 : FONT_SPACE;
	if (type&SIGN && num<0) {
		sign=FONT_MINUS;
		num = -num;
	} else
		sign=(type&PLUS) ? FONT_PLUS : ((type&SPACE) ? FONT_SPACE : 0);
	if (sign) size--;
	if (type&SPECIAL)
		if (base==16) size -= 2;
		else if (base==8) size--;
		i=0;
		if (num==0)
			tmp[i++]= FONT_NUM_0;
		else while (num!=0)
		{
			tmp[i++]=digits[num%base] + 27;
			num/=base;
		}
		if (i>precision) precision=i;
		size -= precision;
		if (!(type&(ZEROPAD+LEFT)))
			while(size-->0)
				*str++ = FONT_SPACE;
		if (sign)
			*str++ = sign;
		if (type&SPECIAL)
			if (base==8)
				*str++ = FONT_NUM_0;
			else if (base==16) {
				*str++ = FONT_NUM_0;
				*str++ = digits[33];
			}
			if (!(type&LEFT))
				while(size-->0)
					*str++ = c;
			while(i<precision--)
				*str++ = FONT_NUM_0;
			while(i-->0)
				*str++ = tmp[i];
			while(size-->0)
				*str++ = FONT_SPACE;
			return str;
}

int Font::vsprintf(GL_TCHAR *buf, const GL_TCHAR *fmt, va_list args)
{
	int len;
	int i;
	GL_TCHAR * str;
	const GL_TCHAR *s;
	int *ip;

	int flags;              /* flags to number() */

	int field_width;        /* width of output field */
	int precision;          /* min. # of digits for integers; max
							number of chars for from string */
	int qualifier;		/* 'h', 'l', or 'L' for integer fields */

	for (str=buf ; fmt && *fmt ; ++fmt) {
		if (*fmt != FONT_PERCENT) {
			*str++ = *fmt;
			continue;
		}

		/* process flags */
		flags = 0;
repeat:
		++fmt;		/* this also skips first '%' */
		switch (*fmt) {
			case FONT_MINUS: flags |= LEFT;    goto repeat;
			case FONT_PLUS: flags |= PLUS;    goto repeat;
			case FONT_SPACE: flags |= SPACE;   goto repeat;
			case FONT_POUND: flags |= SPECIAL; goto repeat;
			case FONT_NUM_0: flags |= ZEROPAD; goto repeat;
		}

		/* get field width */
		field_width = -1;
		if (is_digit(*fmt))
			field_width = skip_atoi(&fmt);
		else if (*fmt == FONT_STAR) {
			/* it's the next argument */
			field_width = va_arg(args, int);
			if (field_width < 0) {
				field_width = -field_width;
				flags |= LEFT;
			}
		}

		/* get the precision */
		precision = -1;
		if (*fmt == FONT_POINT) {
			++fmt;
			if (is_digit(*fmt))
				precision = skip_atoi(&fmt);
			else if (*fmt == FONT_STAR) {
				/* it's the next argument */
				precision = va_arg(args, int);
			}
			if (precision < 0)
				precision = 0;
		}

		/* get the conversion qualifier */
		qualifier = -1;
		if (*fmt == FONT_LOWERCASE_H || *fmt == FONT_LOWERCASE_L || *fmt == FONT_UPPERCASE_L) {
			qualifier = *fmt;
			++fmt;
		}

		switch (*fmt) {
			case FONT_LOWERCASE_C:
				if (!(flags & LEFT))
					while (--field_width > 0)
						*str++ = FONT_SPACE;
				*str++ = (GL_TCHAR) va_arg(args, int);
				while (--field_width > 0)
					*str++ = FONT_SPACE;
				break;

			case FONT_LOWERCASE_S:
				s = va_arg(args, GL_TCHAR *);
				len = STRLEN(s);
				if (precision < 0)
					precision = len;
				else if (len > precision)
					len = precision;

				if (!(flags & LEFT))
					while (len < field_width--)
						*str++ = FONT_SPACE;
				for (i = 0; i < len; ++i)
					*str++ = *s++;
				while (len < field_width--)
					*str++ = FONT_SPACE;
				break;

			case FONT_LOWERCASE_O:
				str = number(str, va_arg(args, unsigned long), 8,
					field_width, precision, flags);
				break;

			case FONT_LOWERCASE_P:
				if (field_width == -1) {
					field_width = 8;
					flags |= ZEROPAD;
				}
				str = number(str,
					(unsigned long) va_arg(args, void *), 16,
					field_width, precision, flags);
				break;

			case FONT_LOWERCASE_X:
				flags |= SMALL;
			case FONT_UPPERCASE_X:
				str = number(str, va_arg(args, unsigned long), 16,
					field_width, precision, flags);
				break;

			case FONT_LOWERCASE_D:
			case FONT_LOWERCASE_I:
//			case 205:
				flags |= SIGN;
			case FONT_LOWERCASE_U:
				str = number(str, va_arg(args, unsigned long), 10,
					field_width, precision, flags);
				break;

			case FONT_LOWERCASE_N:
				ip = va_arg(args, int *);
				*ip = (str - buf);
				break;

			default:
				if (*fmt != FONT_PERCENT)
					*str++ = FONT_PERCENT;
				if (*fmt)
					*str++ = *fmt;
				else
					--fmt;
				break;
		}
	}
	*str = '\0';
	return str-buf;
}
